package com.jinzheng.qhnetty.util.testjinzhengclient;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import lombok.extern.slf4j.Slf4j;

import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.Date;

@Slf4j
public class PlatformTest {
    private static String GPS_TXT = "232302FE4C45575445423134374D4E3130323935320100B7160712130929010203010000000022000000000000020F000000000201010328FFFFFFFF280096FFFF050006AFA5C901EA2C4E060101000201010001010102010101070000000000000000000801010000000000010001010CE409010100013C0A00540300000000001A0000000000000100010001000100000000FFFF02000001002FEA0A7F1E6465706F7433323936302E666C79626565732E636F6D2E636E3A36363538010000001F00010000000000000000000000FB";

    public static void main(String[] args) throws InterruptedException {
        PlatformTest login = new PlatformTest();
        Channel channel = login.getChannel();
        login.cmd05(channel);
        Thread.sleep(5000);
        long ts = System.currentTimeMillis();
        for (int i = 0; i < 101; i++) {
            if (i % 10 == 0) {
                long now = System.currentTimeMillis();
                if (i > 0)
                    log.info("已发送{}条，最近10条数据发送耗时{}ms", i, now - ts);
                ts = now;
            }
            login.doTranspond(channel, GPS_TXT, ts);
        }
    }

    public void doTranspond(Channel channel, String hexStr, long ts) {
        byte[] data = HexUtils.fromHexString(hexStr);
        byte[] newData = new byte[data.length - 3];
        System.arraycopy(data, 2, newData, 0, newData.length);
        System.arraycopy("L0000000000000001".getBytes(), 0, newData, 2, 17);
        {
            SimpleDateFormat sp = new SimpleDateFormat("yyMMddHHmmss");
            long ymdhms = Long.parseLong(sp.format(new Date(ts)));
            int idx = 22;
            newData[idx++] = (byte) (ymdhms / 10000000000L);//年
            newData[idx++] = (byte) (ymdhms / 100000000L % 100);//月
            newData[idx++] = (byte) (ymdhms / 1000000L % 100);//日
            newData[idx++] = (byte) (ymdhms / 10000L % 100);//时
            newData[idx++] = (byte) (ymdhms / 100L % 100);//分
            newData[idx++] = (byte) (ymdhms % 100);//秒
        }
        byte[] escapeData = escape(newData);
        channel.writeAndFlush(escapeData);
    }

    private String host = "127.0.0.1";
    private int port = 15236;
    private String idCode = "00000000000000000";
    private String username = "000000000000";
    private String password = "00000000000000000000";


    public void cmd05(Channel channel) {
        ByteBuffer buffer = ByteBuffer.wrap(new byte[22 + 41]);

        long time = System.currentTimeMillis();
        this.fillHeader(buffer, (byte) 0x05, idCode);
        this.fill05Body(buffer, time, 0, username, password);
        byte[] escapeData = this.escape(buffer.array());
        channel.writeAndFlush(escapeData);
    }

    private Channel getChannel() throws InterruptedException {
        EventLoopGroup group = new NioEventLoopGroup();
        Bootstrap bootstrap = new Bootstrap()
                .group(group)
                //该参数的作用就是禁止使用Nagle算法，使用于小数据即时传输
                .option(ChannelOption.TCP_NODELAY, true)
                .channel(NioSocketChannel.class)
                .handler(new CheckClientInitializer());
        ChannelFuture future = bootstrap.connect(host, port).sync();
        future.channel().closeFuture().addListener(fu -> {
            log.info("连接关闭");
        });
        return future.channel();
    }

    protected void fillHeader(ByteBuffer buffer, byte cmd, String vin) {
        buffer.put(cmd);
        buffer.put((byte) 0xFE);
        splitString(buffer, vin, 17);
        buffer.put((byte) 0x01);
    }

    public void fill05Body(ByteBuffer buffer, long time, int seq, String username, String password) {
        //数据单元长度
        splitInt(buffer, 41, 2);
        //平台登入时间
        SimpleDateFormat sp = new SimpleDateFormat("yyMMddHHmmss");
        long ts = Long.parseLong(sp.format(new Date(time)));
        buffer.put((byte) (ts / 10000000000L));
        buffer.put((byte) (ts / 100000000L % 100));
        buffer.put((byte) (ts / 1000000 % 100));
        buffer.put((byte) (ts / 10000 % 100));
        buffer.put((byte) (ts / 100 % 100));
        buffer.put((byte) (ts % 100));
        //登入流水号
        splitInt(buffer, seq, 2);
        //平台用户名
        splitString(buffer, username, 12);
        //平台密码
        splitString(buffer, password, 20);
        //加密规则
        buffer.put((byte) 0x01);
    }

    public static void splitInt(ByteBuffer buffer, int v, int len) {
        len--;
        while (len >= 0) {
            buffer.put((byte) (v >>> (len * 8)));//右移取高8位
            len--;
        }
    }

    public static void splitString(ByteBuffer buffer, String v, int len) {
        byte[] bytes = v.getBytes(charset);
        int offset = bytes.length - len;
        while (offset < 0) {
            buffer.put((byte) ' ');
            offset++;
        }
        while (offset < bytes.length) {
            buffer.put(bytes[offset++]);
        }
    }

    /**
     * 插入标识位&转义&插入检验码
     */
    public byte[] escape(byte[] origin) {
        byte[] escapes = new byte[origin.length + 3];
        int idx = 0;
        escapes[idx++] = 0x23;
        escapes[idx++] = 0x23;
        byte checkCode = 0x00;
        for (byte ele : origin) {
            checkCode ^= ele;
            escapes[idx++] = ele;
        }
        escapes[idx++] = checkCode;
//        log.info("发送数据：" + HexUtils.toHexString(escapes));
        return escapes;
    }

    public static Charset charset = Charset.forName("GBK");
}
